home *** CD-ROM | disk | FTP | other *** search
/ Computer Music 2004 January / Computer Music Magazine 68 2004.iso / pc / Software / MAC Software / Full Software / Free Effects Mac / Smartelectronix - Bram / Madshifta OS9x OSX / source / madshifta / madshifta.cpp next >
Encoding:
C/C++ Source or Header  |  2002-08-23  |  16.0 KB  |  600 lines

  1. // This is the effect part of the MadShifta source code
  2.  
  3. // All administrative stuff like parameter management is handled here,
  4. // but of course also the implementation of the actual algorithm.
  5.  
  6. // Written by Tobias Fleischer/Tobybear (www.tobybear.de),
  7. // original algorithm source code & additional ideas by Bram from
  8. // SmartElectronix (www.smartelectronix.com)
  9.  
  10. // Even if it is source code, this is meant to be a learning project,
  11. // so don't even try to change just the graphics and sell it :-)
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <math.h>
  16. #include <time.h>
  17.  
  18. #ifndef __madshifta
  19. #include "madshifta.hpp"
  20. #endif
  21.  
  22. #ifndef __madshiftaeditor
  23. #include "madshiftaeditor.hpp"
  24. #endif
  25.  
  26.  
  27. APlugin::APlugin(audioMasterCallback audioMaster)
  28.     : AudioEffectX(audioMaster, kNumPrograms, kNumParams)    // 16 programs, 16 parameters
  29. {
  30.  int i;
  31.  
  32.  // allocate memory for the buffers
  33.  fade = (float*) malloc(sizeof(float) * kFadeSize);
  34.  delay = (float**) malloc(sizeof(float*) * kNumChannels);
  35.  buffer = (float**) malloc(sizeof(float*) * kNumChannels);
  36.  for (i=0; i < kNumChannels; i++)
  37.  {
  38.   delay[i] = (float*) malloc(sizeof(float) * kBufferSize);
  39.   buffer[i] = (float*) malloc(sizeof(float) * kBufferSize);
  40.  }
  41.  
  42.  // create the programs
  43.  programs = new APluginProgram[kNumPrograms];
  44.  
  45.  notecount = 0;
  46.  
  47.  nSize = 10;
  48.  nBuffer = (unsigned) (1 << nSize); // same as 2^10, but faster
  49.  // nBuffer is the buffer size of the fade buffer
  50.  
  51.  inp = 0;
  52.  dp = 1;
  53.  dp = dp-(1 << 12);
  54.  
  55.  suspend(); // empty the buffers
  56.  
  57.  // initialize the crossfading buffer with a raised cosine
  58.  for (i=0; i < nBuffer; i++)
  59.   fade[i] = 0.5f+0.5f*cosf((((float)i/(float)(nBuffer-1))-0.5f)*2.0f*3.141592f);
  60.  
  61.  editor = new APluginEditor(this);
  62.  srand((unsigned int)time(NULL)); // important if you use the rand() function!
  63.  
  64.  // set some important variables, according to the constants
  65.  // you specified at the beginning of this file
  66.  hasVu(false);
  67.  setNumInputs(kNumInputs);
  68.  setNumOutputs(kNumOutputs);
  69.  canMono(kCanMono);
  70.  canProcessReplacing(kCanReplacing);
  71.  isSynth(kIsSynth);
  72.  setUniqueID(kID);
  73.  
  74.  // initial program names
  75.  for (i=0; i < kNumPrograms; i++)
  76.   sprintf(programs[i].name, "Mad Mother %02d", i+1);
  77.  curProgram = 0;    // eh?
  78.  setProgram(0);
  79. }
  80.  
  81. APlugin::~APlugin()
  82. {
  83.  // deallocate the buffers
  84.  free(fade);
  85.  for (int i=0; i < kNumChannels; i++)
  86.  {
  87.   free(delay[i]);
  88.   free(buffer[i]);
  89.  }
  90.  free(delay);
  91.  free(buffer);
  92.  
  93.  // destroy the created programs
  94.  delete[] programs;
  95. }
  96.  
  97. // this is the filter section, currently a simple LP/HP filter
  98. // is included, but this could be extended
  99. float APlugin::DoFilter(float i, float cutoff, float res, unsigned char ch)
  100. {
  101.  float fb;
  102.  
  103.  fb = res + res/(1.0f-cutoff); // calculate feedback for resonance setting
  104.  old1[ch] = old1[ch] + cutoff*(i-old1[ch]+fb*(old1[ch]-old2[ch]));
  105.  old2[ch] = old2[ch] + cutoff*(old1[ch]-old2[ch]);
  106.  if (fFType < 0.5f) return old2[ch];  // return lowpass filtered signal
  107.  else return i-old2[ch]; // return highpass filtered signal
  108. }
  109.  
  110. // This is the processing routine that is called for every sample
  111. // from process() or processReplacing()
  112. // In its current implementation, i[0] contains the left channel,
  113. // i[1] the right channel, but this could be extended to more channels.
  114. // NOTE: arrays are generally not the fastest way to access memory
  115. // locations, but they show the structured approach better than direct
  116. // pointer access. But feel free to change that... :-)
  117.  
  118. // The algorithm goes like this:
  119. // out = filter(pitchshift(input + delay(out)*feedback))*volume
  120.  
  121. void APlugin::DoProcess(float *i)
  122. {
  123.  float a, b;
  124.  unsigned int ul1, ul2;
  125.  unsigned char ch;
  126.  
  127.  // increasing the delay buffer pointers, including
  128.  // some more power-of-2 automatic wrap arounds
  129.  delay_in = (delay_in+1) & (nDelay-1);
  130.  delay_out = (delay_out+1) & (nDelay-1);
  131.  
  132.  ul1 = p1 >> 12; // the '12' is to keep the accuracy...
  133.  ul2 = p2 >> 12;
  134.  
  135.  for (ch=0; ch < kNumChannels; ch++) // currently this is intended for 2 channels!
  136.  {
  137.   // write last value at delay_in in delay buffer + denormal fix
  138.   delay[ch][delay_in] = last[ch] + p4;
  139.  
  140.   // store input value in buffer + feedback of delay buffer at delay_out
  141.   buffer[ch][inp] = i[ch] + fDelayFB*delay[ch][delay_out] + p4;
  142.  
  143.   // apply the fading to smooth things
  144.   a = buffer[ch][(inp-ul1) & (nBuffer-1)] * fade[ul1 & (nBuffer-1)];
  145.   b = buffer[ch][(inp-ul2) & (nBuffer-1)] * fade[ul2 & (nBuffer-1)];
  146.  
  147.   // apply filter & denormal fix
  148.   last[ch] = DoFilter(a+b, cut, reso, ch) + p4;
  149.  
  150.   a = fDryWet * last[ch];
  151.  
  152.   // do hard clipping, could be improved by saturation shaping:
  153.   if (a > 1.0f) a = 1.0f; else if (a < -1.0f) a = -1.0f;
  154.  
  155.   // mix processed/unprocessed signal
  156.   i[ch] = i[ch]*(1.0f-fDryWet) + a + p4;
  157.  }
  158.  p1 = p1 - dp;
  159.  p2 = p2 - dp;
  160.  
  161.  // increase/wrap input pointer
  162.  inp = (inp+1) & (nBuffer-1);
  163. }
  164.  
  165. void APlugin::process(float **inputs, float **outputs, long sampleFrames)
  166. {
  167.  float inp[2];
  168.  int i;
  169.  
  170.  for (i=0; i < sampleFrames; i++)
  171.  {
  172.   inp[0] = inputs[0][i];
  173.   inp[1] = inputs[1][i];
  174.   DoProcess(inp);
  175.   outputs[0][i] += inp[0] * fOutVol;
  176.   outputs[1][i] += inp[1] * fOutVol;
  177.  }
  178. }
  179.  
  180. void APlugin::processReplacing(float **inputs, float **outputs, long sampleFrames)
  181. {
  182.  float inp[2];
  183.  int i;
  184.  
  185.  for (i=0; i < sampleFrames; i++)
  186.  {
  187.   inp[0] = inputs[0][i];
  188.   inp[1] = inputs[1][i];
  189.   DoProcess(inp);
  190.   outputs[0][i] = inp[0] * fOutVol;
  191.   outputs[1][i] = inp[1] * fOutVol;
  192.  }
  193. }
  194.        
  195. // In this procedure, incoming MIDI events are handled
  196. long APlugin::processEvents(VstEvents *ev)
  197. {
  198.  long root, note, i, status;
  199.  float s, nvol;
  200.  VstMidiEvent *event;
  201.  char *midiData;
  202.  
  203.  for (i=0; i < ev->numEvents; i++)
  204.  {
  205.   if ( (ev->events[i])->type == kVstMidiType )
  206.   {
  207.    event = (VstMidiEvent*) (ev->events[i]); // get current event
  208.    midiData = event->midiData;
  209.    status = midiData[0] & 0xF0; // channel information is removed
  210.    if ( (status == 0x90) && (midiData[2] > 0) ) // "note on" ?
  211.    {
  212.     note = (midiData[1] & 0x7F); // midi note
  213.     root = rootKeyScaled(fRoot);
  214.     notecount++;
  215.     if (notecount == 1) oldtune = fTune;
  216.     s = (float)(note-root) / (float)(kTuneMax-kTuneMin) + 0.5f;
  217.     setParameter(kTune, s); // recalculate the tuning
  218.    }
  219.    else if ( ((status == 0x90) && (midiData[2] == 0)) || (status == 0x80) ) // "note off" ?
  220.    {
  221.     notecount--;
  222.     if (notecount <= 0)
  223.     {
  224.      notecount = 0;
  225.      if (fMMode < 0.5f) setParameter(kTune, oldtune);
  226.     }
  227.    }
  228.    else if (status == 0xB0) // Midi CC ?
  229.    {
  230.     note = midiData[1]; // Midi CC#
  231.     nvol = (float)midiData[2] / 127.0f; // CC data
  232.     switch (note)
  233.     {
  234.      case kCC_Tune: setParameter(kTune, nvol); break;
  235.      case kCC_Fine: setParameter(kFine, nvol); break;
  236.      case kCC_Length: setParameter(kDelayLen, nvol); break;
  237.      case kCC_Reso: setParameter(kResonance, nvol); break;
  238.      case kCC_Feedback: setParameter(kDelayFB, nvol); break;
  239.      case kCC_DryWet: setParameter(kDryWet, nvol); break;
  240.      case kCC_Cutoff: setParameter(kCutoff, nvol); break;
  241.      case kCC_OutVol: setParameter(kOutVol, nvol); break;
  242.      default: break;
  243.     }
  244.    }
  245.   }
  246.  }
  247.  return 1;
  248. }
  249.  
  250. long APlugin::canDo(char *text)
  251. {
  252.  if (strcmp(text,"receiveVstEvents") == 0) return 1; // can do
  253.  if (strcmp(text,"receiveVstMidiEvent") == 0) return 1; // can do
  254.  if (strcmp(text,"plugAsChannelInsert") == 0) return 1; // can do
  255.  if (strcmp(text,"plugAsSend") == 0) return 1; // can do
  256.  if (strcmp(text,"mixDryWet") == 0) return 1; // can do
  257.  if (kNumChannels == 2)
  258.  {
  259.   if (strcmp(text,"2in2out") == 0) return 1; // can do
  260.   if (kCanMono)
  261.    if (strcmp(text,"1in2out") == 0) return 1; // can do
  262.  }
  263.  else if (kNumChannels == 1)
  264.  {
  265.   if (strcmp(text,"1in1out") == 0) return 1; // can do
  266.  }
  267.  
  268.  return -1;    // explicitly can't do
  269. }
  270.  
  271. APluginProgram::APluginProgram()
  272. {
  273.  // Here the parameters for a program are inititialized
  274.  fDryWet = 1.0f;
  275.  fFine = 0.5f;
  276.  fTune = 0.5f;
  277.  fRoot = 36.0f/100.0f;
  278.  fMMode = 0.0f;
  279.  fDelayLen = 0.0f;
  280.  fDelayFB = 0.0f;
  281.  fCutoff = 1.0f;
  282.  fResonance = 0.0f;
  283.  fFType = 0.0f;
  284.  fOutVol = 1.0f;
  285.  strcpy(name, "Init"); // set program name
  286. }
  287.  
  288. void APlugin::setProgram(long aProgram)
  289. {
  290.  if ( (aProgram < 0) || (aProgram > (kNumPrograms-1)) ) return;
  291.  
  292.  curProgram = aProgram;
  293.  // all parameters have to be set here for a program change
  294.  setParameter(kDryWet, programs[curProgram].fDryWet);
  295.  setParameter(kFine, programs[curProgram].fFine);
  296.  setParameter(kTune, programs[curProgram].fTune);
  297.  setParameter(kRoot, programs[curProgram].fRoot);
  298.  setParameter(kMMode, programs[curProgram].fMMode);
  299.  setParameter(kDelayLen, programs[curProgram].fDelayLen);
  300.  setParameter(kDelayFB, programs[curProgram].fDelayFB);
  301.  setParameter(kCutoff, programs[curProgram].fCutoff);
  302.  setParameter(kResonance, programs[curProgram].fResonance);
  303.  setParameter(kFType, programs[curProgram].fFType);
  304.  setParameter(kOutVol, programs[curProgram].fOutVol);
  305.  
  306.  // tell the host to update the editor display with the new settings
  307.  AudioEffectX::updateDisplay();
  308. }
  309.  
  310. void APlugin::setProgramName(char *name)
  311. {
  312.  strcpy(programs[curProgram].name, name);
  313. }
  314.  
  315. void APlugin::getProgramName(char *name)
  316. {
  317.  strcpy(name, programs[curProgram].name);
  318. }
  319.  
  320. bool APlugin::getProgramNameIndexed(long category, long index, char *text)
  321. {
  322.  if (index < kNumPrograms)
  323.  {
  324.   strcpy(text, programs[index].name);
  325.   return true;
  326.  }
  327.  return false;
  328. }
  329.  
  330. void APlugin::suspend()
  331. {
  332.  // empty those buffers!
  333.  for (int i=0; i < kNumChannels; i++)
  334.  {
  335.   for (int j=0; j < kBufferSize; j++)
  336.   {
  337.    buffer[i][j] = 0.0f;
  338.    delay[i][j] = 0.0f;
  339.   }
  340.  }
  341. }
  342.  
  343. void APlugin::resume()
  344. {
  345.  wantEvents(1); // important for all plugins that receive MIDI!
  346. }
  347.  
  348. float APlugin::getVu()
  349. {
  350.  float cvu = vu;
  351.  vu = 0.0f;
  352.  return cvu;
  353. }
  354.  
  355. void APlugin::setParameter(long index, float value)
  356. {
  357.  double f;
  358.  
  359.  // value HAS to be between 0 and 1 !!!
  360.  if (value > 1.0f) value = 1.0f;
  361.  else if (value < 0.0f) value = 0.0f;
  362.  
  363.  if (editor)
  364.   ((AEffGUIEditor*)editor)->setParameter(index, value);
  365.  
  366.  switch (index)
  367.  {
  368.   case kFine:
  369.    fFine = value; programs[curProgram].fFine = value;
  370.    // recalculate tune and finetune values for the algorithm:
  371.    semitones = tuneScaled(fTune);
  372.    f = powerof2(semitones/12.0);
  373.    dp = (unsigned long) round(((0.5f-fFine)*(f*0.25f)+f)*(float)(1 << 12));
  374.    dp = dp-(1 << 12);
  375.    break;
  376.   case kTune:
  377.    // recalculate tune and finetune values for the algorithm:
  378.    fTune = value; programs[curProgram].fTune = value;
  379.    semitones = tuneScaled(fTune);
  380.    f = powerof2(semitones/12.0);
  381.    dp = (unsigned long) round(((0.5-fFine)*(f*0.25)+f)*(double)(1 << 12));
  382.    dp = dp-(1 << 12);
  383.    break;
  384.   case kDelayLen:
  385.    fDelayLen = value; programs[curProgram].fDelayLen = value;
  386.    // logarithmic scale for this control:
  387.    value = round(-500.0f*log10((1.0f-value)+0.01f))/2000.0f;
  388.    // lower boundary:
  389.    if (value < 0.0001f) value = 0.0001f;
  390.    displace = (unsigned long)round(44100.0f*value) + 1;
  391.    nDelay = n_larger(displace);
  392.    delay_in = 0;
  393.    // nifty wrap-around:
  394.    delay_out = (delay_in-displace) & (nDelay-1);
  395.    inp = 0;
  396.    p1 = 0;
  397.    p2 = (nBuffer >> 1) << 12; // p2 starts at center of fade
  398.    break;
  399.   case kCutoff:
  400.    cut = value;
  401.    // simple boundary check for filter cutoff (to keep it stable):
  402.    if (value > 0.99f) cut = 0.99f;
  403.    else if (value < 0.01f) cut = 0.01f;
  404.    fCutoff = value; programs[curProgram].fCutoff = value;
  405.    break;
  406.   case kResonance:
  407.    // simple boundary check for filter resonance (to keep it stable):
  408.    reso = value; if (value > 0.98f) reso = 0.98f;
  409.    fResonance = value; programs[curProgram].fResonance = value;
  410.    break;
  411.   // these go regularly:
  412.   case kDryWet: fDryWet = value; programs[curProgram].fDryWet = value; break;
  413.   case kDelayFB: fDelayFB = value; programs[curProgram].fDelayFB = value; break;
  414.   case kFType: fFType = value; programs[curProgram].fFType = value; break;
  415.   case kRoot: fRoot = value; programs[curProgram].fRoot = value; break;
  416.   case kMMode: fMMode = value; programs[curProgram].fMMode = value; break;
  417.   case kOutVol: fOutVol = value; programs[curProgram].fOutVol = value; break;
  418.   default: break;
  419.  }
  420. }
  421.  
  422. float APlugin::getParameter(long index)
  423. {
  424.  switch (index)
  425.  {
  426.   case kDryWet: return fDryWet;
  427.   case kFine: return fFine;
  428.   case kTune: return fTune;
  429.   case kRoot: return fRoot;
  430.   case kMMode: return fMMode;
  431.   case kDelayLen: return fDelayLen;
  432.   case kDelayFB: return fDelayFB;
  433.   case kCutoff: return fCutoff;
  434.   case kResonance: return fResonance;
  435.   case kFType: return fFType;
  436.   case kOutVol: return fOutVol;
  437.   default: return 0.0f;
  438.  }
  439. }
  440.  
  441. void APlugin::getParameterName(long index, char *text)
  442. {
  443.  switch (index)
  444.  {
  445.   case kFine: strcpy(text, "FineTune"); break;
  446.   case kDryWet: strcpy(text, "DryWet"); break;
  447.   case kTune: strcpy(text, "Tune"); break;
  448.   case kRoot: strcpy(text, "Root"); break;
  449.   case kMMode: strcpy(text, "MidiMode"); break;
  450.   case kDelayLen: strcpy(text, "DelayLen"); break;
  451.   case kDelayFB: strcpy(text, "DelayFB"); break;
  452.   case kCutoff: strcpy(text, "Cutoff"); break;
  453.   case kResonance: strcpy(text, "Reso"); break;
  454.   case kFType: strcpy(text, "FltType"); break;
  455.   case kOutVol: strcpy(text, "OutVol"); break;
  456.   default: strcpy(text, "reserved"); break;
  457.  }
  458. }
  459.  
  460. void APlugin::getParameterDisplay(long index, char *text)
  461. {
  462.  switch (index)
  463.  {
  464.   case kTune:
  465.    sprintf(text, "%d", tuneScaled(fTune));
  466.    break;
  467.   case kFine:
  468.    sprintf(text, "%d", (int)fineTuneScaled(fFine));
  469.    break;
  470.   case kRoot:
  471.    strcpy(text, midiNoteNames[rootKeyScaled(fRoot)]);
  472.    break;
  473.   case kDryWet:
  474.   case kOutVol:
  475.   case kDelayLen:
  476.   case kDelayFB:
  477.   case kCutoff:
  478.   case kResonance:
  479.    sprintf(text, "%d", (int)(getParameter(index)*100.0f));
  480.    break;
  481.   case kFType:
  482.    if (fFType < 0.5f)
  483.     strcpy(text, "lowpass");
  484.    else
  485.     strcpy(text, "highpass");
  486.    break;
  487.   case kMMode:
  488.    if (fMMode < 0.5f)
  489.     strcpy(text, "back");
  490.    else
  491.     strcpy(text, "hold");
  492.    break;
  493.   default:
  494.    strcpy(text, "-");
  495.    break;
  496.  }
  497. }
  498.  
  499. void APlugin::getParameterLabel(long index, char *text)
  500. {
  501.  switch (index)
  502.  {
  503.   case kDryWet:
  504.   case kOutVol:
  505.   case kDelayLen:
  506.   case kDelayFB:
  507.   case kCutoff:
  508.   case kResonance:
  509.    strcpy(text, "%");
  510.    break;
  511.   case kTune:
  512.    strcpy(text, "semitones");
  513.    break;
  514.   case kFine:
  515.    strcpy(text, "cents");
  516.    break;
  517.   default:
  518.    strcpy(text, " ");
  519.    break;
  520.  }
  521. }
  522.  
  523. bool APlugin::getEffectName(char *name)
  524. {
  525.  strcpy(name, kEffectName);
  526.  return true;
  527. }
  528.  
  529. bool APlugin::getVendorString(char *text)
  530. {
  531.  strcpy(text, kVendor);
  532.  return true;
  533. }
  534.  
  535. bool APlugin::getProductString(char *text)
  536. {
  537.  strcpy(text, kProduct);
  538.  return true;
  539. }
  540.  
  541. long APlugin::getVendorVersion()
  542. {
  543.  return kVersion; // return version number
  544. }
  545.  
  546. bool APlugin::getOutputProperties(long index, VstPinProperties *properties)
  547. {
  548.  if ( (index >= 0) && (index < kNumOutputs) )
  549.  {
  550.   sprintf (properties->label, "%s %ld", kChannelID, index+1);
  551.   sprintf (properties->shortLabel, "%s %ld", kChannelID, index+1);
  552.   properties->flags = kVstPinIsActive;
  553.   if (index < 2)
  554.    properties->flags = properties->flags | kVstPinIsStereo;
  555.   return true;
  556.  }
  557.  return false;
  558. }
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566. //-----------------------------------------------------------------------------
  567. //                                   main()                                   |
  568. //-----------------------------------------------------------------------------
  569.  
  570. // prototype of the export function main
  571. #if BEOS
  572. #define main main_plugin
  573. extern "C" __declspec(dllexport) AEffect *main_plugin(audioMasterCallback audioMaster);
  574.  
  575. #else
  576. AEffect *main(audioMasterCallback audioMaster);
  577. #endif
  578.  
  579. AEffect *main(audioMasterCallback audioMaster)
  580. {
  581.     // get vst version
  582.     if ( !audioMaster(0, audioMasterVersion, 0, 0, 0, 0) )
  583.         return 0;  // old version
  584.  
  585.     AudioEffect* effect = new APlugin(audioMaster);
  586.     if (!effect)
  587.         return 0;
  588.     return effect->getAeffect();
  589. }
  590.  
  591. #if WIN32
  592. void* hInstance;
  593. BOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpvReserved)
  594. {
  595.     hInstance = hInst;
  596.     return 1;
  597. }
  598. #endif
  599.  
  600.